package es.duma.util.xsl;

import es.duma.util.log.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;


import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

import java.net.URLConnection;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import net.sf.saxon.om.Item;
import net.sf.saxon.om.NodeInfo;


/**
 * Funciones que extienden el procesador xsl
 */
public class XSLfunctions {
    
    
    public XSLfunctions() {
    
    }
    
    /** Funcion para testear el uso de estas funciones desde una plantilla xsl */
    public static String holaMundo(String saludo){
        return "Hola Mundo "+saludo;
    }
    
    
    /**
     * Realiza una peticion REST (HTTP GET a la url pasada por parametro
     * @param urlREST url para hacer la peticion
     * @return el resultado obtenido en la peticion se devuelve en un objeto Source
     */
    public static Source requestRESTsource(String urlREST){
        //Se lanza la  busqueda a la direccion REST obtenida en el paso anterior
        InputStream in=null;
        HttpURLConnection connection=null;
        URL url;
                
        try {
            url = new URL(urlREST);
            connection = (HttpURLConnection)url.openConnection();
            Log.debug("[XSLfunctions] Conexion Http establecida "+urlREST);
        }catch (MalformedURLException e) {
            Log.error("[XSLfunctions] Error al formar la URL "+e);
        }catch (IOException e) {
            Log.error("[XSLfunctions] No se puede conectar");
        }

        try {
            in = connection.getInputStream();
        } catch (IOException e) {
            Log.error("[XSLfunctions] Error al obtener el inputStream en la conexion "+e);
        }
        
        Source result = new StreamSource(in);
        return result;
    }
    
    
    /**
     * Realiza una peticion REST (HTTP GET a la url pasada por parametro
     * @param urlREST url para hacer la peticion
     * @return el resultado obtenido en la peticion se devuelve como un String
     */
    public static String requestREST(String urlREST){
        //Se lanza la  busqueda a la direccion REST obtenida en el paso anterior
        InputStream in=null;
        HttpURLConnection connection=null;
        URL url;
        Long ini=System.currentTimeMillis();
        
        try {
            url = new URL(urlREST);
            connection = (HttpURLConnection)url.openConnection();
            Log.debug("[XSLfunctions] Conexion Http establecida");
        }catch (MalformedURLException e) {
            Log.error("[XSLfunctions] Error al formar la URL "+e);
        }catch (IOException e) {
            Log.error("[XSLfunctions] No se puede conectar");
        }

        try {
            in = connection.getInputStream();
        } catch (IOException e) {
            Log.error("[XSLfunctions] Error al obtener el inputStream en la conexion "+e);
        }

        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        StringBuilder result = new StringBuilder();
        String line = null;
        try {
            while ((line = br.readLine()) != null) {
                result.append(line + "\n");
            }
            br.close();
        } catch (IOException e) {
            Log.error("[XSLfunctions] Error al obtener el inputStream en un String "+e);
        }
        
        Log.debug("Se realiza la desconexion http");
        connection.disconnect(); 
        Long fin=System.currentTimeMillis();
        Log.debug("[XSLfunctions][TIME] Tiempo empleado en la conexion HTTP:-> "+urlREST+" "+(fin-ini)+ "ms");
       
        return result.toString();
    }


    /*
        public static String requestRESTConcurrente(String urlREST){
        Long ini=System.currentTimeMillis();
        
        // Lista de los hilos que se ejecutan en el programa
        ArrayList listaHilos=new ArrayList(10);
        
        // Contador de conexiones activas
        int hilosTerminados[]=new int[1];
        
        // Lista de resultados obtenidos
        ArrayList results=new ArrayList(listaHilos.size());

        //Se crea un grupo de hilos
        ThreadGroup threadGroup =new ThreadGroup("conexions");
       
        // Lanzamiento de todas las peticiones REST, un hilo por peticion
        for (int i=0;i<2;i++){
            Thread hilo = new Thread(threadGroup, new ConcurrentConexion(urlREST,i,results,hilosTerminados));
            Log.debug("[HILO] [Concurrent] Creado hilo"+i);
           hilosTerminados[0]++;
            hilo.start();
        }
                
        // Eperamos a que terminen todos los hilos
        Log.debug("Esperamos a que terminen las conexiones de todos los hilos");
        while (hilosTerminados[0]>0){
            
        }
        
                
        Long fin=System.currentTimeMillis();
        Log.debug("[XSLfunctions][TIME] Tiempo total empleado en las conexiones HTTP:-> "+urlREST+" "+(fin-ini)+ "ms");
        
        Log.debug("TODO HA TERMINADO");
        Iterator it=results.iterator();
        String mergeResult="";
        while (it.hasNext()){
            mergeResult+=(String)it.next();
            Log.debug(mergeResult);
        }
        
        return mergeResult;
    }
    */
    
    
    /**
     * Funcion para testear el uso de listas (xsl:sequence) desde plantillas xsl
     * @param baseUrl
     * @param lista
     * @return
     */
    public static String pruebaLista(String baseUrl,List lista){
        Iterator it=lista.iterator();
        String aux="";
        
        while (it.hasNext()){
            Log.debug("TEST "+baseUrl+ ((Item)it.next()).getStringValue());
        }

        return ""+lista.size();
    }
    
    
    /**
     * Funcion de extension del procesador xsl.
     * Realiza las peticiones REST (http get) a las direcciones pasadas en la lista urlREST de manera concurrente
     * @param baseUrl base de la direccion donde realizar la peticion
     * @param urlsREST lista de direcciones (la parte no comun de la direccion) donde realizar las peticiones concurrentes
     * @return el resultado de devulve en una lista una vez han conluido todas las peticiones.
     * La lista esta rellena de un resultado para cada una de las peticiones
     */
    public static List requestRESTConcurrenteList2(String baseUrl,List urlsREST){
        Long ini=System.currentTimeMillis();
        
        if (urlsREST.size()==0){
            Log.debug("[XSLfunctions] No hay peticiones concurrentes para realizar");
            return null;
        }
            
        // Contador de conexiones terminadas
        int hilosTerminados[]=new int[1];
        hilosTerminados[0]=0;
        Log.debug("Hilos terminados "+hilosTerminados[0]);
        
        // Lista de resultados obtenidos
        Log.debug("[XSLfunctions] Llamada desde un xsl para realizar "+urlsREST.size()+" conexiones concurrentes");
        ListaResultados results=new ListaResultados(urlsREST.size(),hilosTerminados);

        //Se crea un grupo de hilos
        ThreadGroup threadGroup =new ThreadGroup("conexions");
       
        // Lanzamiento de todas las peticiones REST, un hilo por peticion
        Iterator it=urlsREST.iterator();
        int i=0;
        while (it.hasNext()){
            // Se construye la direccion de peticion rest
            String urlREST=baseUrl+((Item)it.next()).getStringValue();
            Thread hilo = new Thread(threadGroup, new ConcurrentConexion(urlREST,i++,results,hilosTerminados));
             // Se incrementa el contador de conexiones activas
            //hilosEjecutandose[0]++;
            hilo.start();            
        }
        


        //
        Log.debug("[XSLfunctions] Se solicita el resultado final generado por los hilos lanzados \n");
        List aux=null;
        aux = results.getListaSync();
        Log.debug("[XSLfunctions] Se ha podido acceder a la lista con los resultados ");
        
        Long fin=System.currentTimeMillis();
        Log.debug("[XSLfunctions][TIME] Tiempo total empleado en las conexiones HTTP:->"+(fin-ini)+ "ms");
       


        //Escribir el contenido de la lista en el log
        /*
        Iterator it2=aux.iterator();
        while (it2.hasNext()){
            Log.debug("/////// "+(String)it2.next());
        }
        */
                
        return aux;
    }
}
